using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Security.Cryptography;

namespace Lizk.Utilities
{
    /// <summary>
    /// Encapsulates useful image functions
    /// </summary>
    public class ImageTools
    {
        /// <summary>
        /// Describes a result from a Compare operation.
        /// </summary>
        public enum CompareResult
        {
            /// <summary>
            /// The Images are equal
            /// </summary>
            ciCompareOk,
            /// <summary>
            /// The images are does not have the same pixels
            /// </summary>
            ciPixelMismatch,
            /// <summary>
            /// The Size of the images are not the same
            /// </summary>
            ciSizeMismatch
        };

        /// <summary>
        /// Compares two images. Code originally from http://www.codeproject.com/dotnet/comparingimages.asp
        /// </summary>
        /// <param name="bmp1">First image to be compared</param>
        /// <param name="bmp2">Second image to be compared</param>
        /// <returns>A CompareResult enum that describes if the images are alike, has different sizes or mismatching pixels.</returns>
        public static CompareResult Compare(Bitmap bmp1, Bitmap bmp2)
        {
            CompareResult cr = CompareResult.ciCompareOk;

            //Test to see if we have the same size of image
            if (bmp1.Size != bmp2.Size)
            {
                cr = CompareResult.ciSizeMismatch;
            }
            else
            {
                //Convert each image to a byte array
                System.Drawing.ImageConverter ic = new System.Drawing.ImageConverter();
                byte[] btImage1 = new byte[1];
                btImage1 = (byte[])ic.ConvertTo(bmp1, btImage1.GetType());
                byte[] btImage2 = new byte[1];
                btImage2 = (byte[])ic.ConvertTo(bmp2, btImage2.GetType());

                //Compute a hash for each image
                SHA256Managed shaM = new SHA256Managed();
                byte[] hash1 = shaM.ComputeHash(btImage1);
                byte[] hash2 = shaM.ComputeHash(btImage2);

                //Compare the hash values
                for (int i = 0; i < hash1.Length && i < hash2.Length && cr == CompareResult.ciCompareOk; i++)
                {
                    if (hash1[i] != hash2[i])
                        cr = CompareResult.ciPixelMismatch;
                }
            }
            return cr;
        }

        /// <summary>
        /// Resizes an image.
        /// </summary>
        /// <param name="image">The image to resize</param>
        /// <param name="targetSize">The canvas to make the original image fit to.</param>
        /// <param name="constrainProportions">Whether or not to constrain the proportions of the original image</param>
        /// <param name="mode">The mode of interpolation.</param>
        /// <returns>A resized image.</returns>
        public static Image Resize(Image image, Size targetSize, bool constrainProportions, InterpolationMode mode)
        {
            

            int destHeight = 0, destWidth = 0, destX = 0, destY = 0;

            double sProportion = (double)targetSize.Width / (double)targetSize.Height;
            double iProportion = (double)image.Width / (double)image.Height;
            double pDiff = sProportion - iProportion;
            if (pDiff < 0) pDiff = -1 * pDiff;


            if (sProportion > iProportion && constrainProportions)
            {
                destHeight = targetSize.Height;
                destWidth = (int)(((double)targetSize.Height / (double)image.Height) * (double)image.Width);
                destX = (targetSize.Width - destWidth) / 2;
            }
            else if (sProportion < iProportion && constrainProportions)
            {
                destWidth = targetSize.Width;
                destHeight = (int)(((double)targetSize.Width / (double)image.Width) * (double)image.Height);
                destY = (targetSize.Height - destHeight) / 2;
            }
            else
            {
                destWidth = targetSize.Width;
                destHeight = targetSize.Height;
            }

            Bitmap bmPhoto = new Bitmap(targetSize.Width, targetSize.Height, PixelFormat.Format32bppArgb);
            bmPhoto.SetResolution(image.HorizontalResolution, image.VerticalResolution);

            Graphics grPhoto = Graphics.FromImage(bmPhoto);
            grPhoto.Clear(Color.Transparent);
            grPhoto.InterpolationMode = mode;

            grPhoto.DrawImage(image, new Rectangle(destX, destY, destWidth, destHeight), new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);

            grPhoto.Dispose();
            image.Dispose();
            return bmPhoto;
        }
    }
}
